package com.zlq.cn.admin.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlq.cn.admin.domain.Menu;
import com.zlq.cn.admin.domain.Role;
import com.zlq.cn.admin.domain.vo.AdminVo;
import com.zlq.cn.admin.mapper.MenuMapper;
import com.zlq.cn.admin.mapper.RoleMapper;
import one.util.streamex.StreamEx;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.PatternMatchUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MenuService extends ServiceImpl<MenuMapper, Menu> {

    @Resource
    private MenuMapper menuMapper;
    @Resource
    private RoleMapper roleMapper;

    /**
     * 获取管理员菜单列表
     *
     * @return
     */
    public List<Menu> getAdminMenuList() {
        AdminVo adminUser = AdminTokenService.requestUser();
        Role role = roleMapper.selectById(adminUser.getRoleId());
        List<Menu> menus = new ArrayList<>(0);
        if (role == null || StringUtils.isEmpty(role.getMenuIds())) {
            if (adminUser.getMaster() == 1) {
                menus = super.lambdaQuery()
                        .eq(Menu::getType, 0)
                        .orderByDesc(Menu::getWeight)
                        .list();
            } else {
                return menus;
            }
        } else {
            menus = super.lambdaQuery()
                    .eq(Menu::getType, 0)
                    .inSql(adminUser.getMaster() == 0, Menu::getId, role.getMenuIds())
                    .orderByDesc(Menu::getWeight)
                    .list();

        }
        return getChildren(menus);
    }

    /**
     * 获取菜单列表
     *
     * @return
     */
    public List<Menu> getList(String title, Integer type) {
        List<Menu> menus = menuMapper.selectList(new QueryWrapper<Menu>().eq(type != null, "type", type).orderByDesc("weight"));
        if (!StringUtils.isEmpty(title)) {
            List<Menu> matchList = menus.stream().filter(menu ->
                            isMatchTitle(menu.getTitle(), title) ||
                                    isMatchTitle(menu.getComponent(), title) ||
                                    isMatchTitle(menu.getName(), title) ||
                                    isMatchTitle(menu.getPath(), title)
                    )
                    .collect(Collectors.toList());
            List<Integer> ids = matchList.stream().map(Menu::getId).collect(Collectors.toList());
            HashSet<Integer> matchIds = new HashSet<>();
            matchIds.addAll(ids);
            getParentIds(menus, ids, matchIds);
            menus = menus.stream().filter(item -> matchIds.contains(item.getId())).collect(Collectors.toList());
        }

        return getChildren(menus);
    }


    public boolean isMatchTitle(String content, String title) {
        if (content == null) {
            return false;
        }
        return content.contains(title) || PatternMatchUtils.simpleMatch(title, content);
    }

    public void getParentIds(List<Menu> menus, List<Integer> ids, Set<Integer> matchIds) {
        List<Integer> parentIds = menus.stream().filter(menu -> ids.contains(menu.getId())).map(Menu::getParentId).collect(Collectors.toList());
        if (!parentIds.isEmpty()) {
            matchIds.addAll(parentIds);
            getParentIds(menus, parentIds, matchIds);
        }
    }

    /**
     * 获取子节点
     */
    private List<Menu> getChildren(List<Menu> all) {
        if (all == null) {
            return null;
        }
        Map<Integer, Menu> menuMap = StreamEx.of(all)
                .toMap(Menu::getId, Function.identity());
        Iterator<Menu> iterator = all.iterator();
        while (iterator.hasNext()) {
            Menu menu = iterator.next();
            menu.setChildren(new ArrayList<>());
            if (menu.getParentId() != null) {
                Menu parentMenu = menuMap.get(menu.getParentId());
                if (parentMenu != null) {
                    parentMenu.getChildren().add(menu);
                }
                iterator.remove();
            }
        }
        return all;
    }


    /**
     * 删除菜单
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        menuMapper.deleteById(id);
        List<Integer> pidList = Arrays.asList(id);
        while (true) {
            List<Menu> children = menuMapper.selectList(new QueryWrapper<Menu>().in("parentId", pidList));
            if (children.isEmpty()) {
                break;
            }
            pidList = children.stream().map(Menu::getId).collect(Collectors.toList());
            menuMapper.delete(new UpdateWrapper<Menu>().in("id", pidList));
        }
    }

    /**
     * 新增或修改菜单
     *
     * @param menu
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(Menu menu) {
        Assert.hasText(menu.getTitle(), "菜单名称不能为空");
        Assert.hasText(menu.getPath(), "菜单路径不能为空");
        Assert.notNull(menu.getIsApi(), "请选择创建菜单或权限");
        menu.setHidden(menu.getHidden() == null ? false : menu.getHidden());
        if (menu.getIsApi()) {
            Assert.notNull(menu.getParentId(), "权限必须选择上级菜单");
        }
        if (menu.getId() == null) {
            menu.insert();
        } else {
            if (menu.getId().equals(menu.getParentId())) {
                menu.setParentId(null);
            }
            menuMapper.updateById(menu);
//            menu.update(new UpdateWrapper<Menu>()
//                    .set("parentId", menu.getParentId())
//                    .eq("id", menu.getId())
//            );
        }
        return Boolean.TRUE;
    }
}
